# tag_timeit.py
"""Compare different forms of Tag class for performance"""

from timeit import timeit
from collections import namedtuple


# Set up short name and setup string for import
Impl = namedtuple("Impl", "name imports") 
implementations = [Impl(*x) for x in (
    ("pyd0.9.8", "from dicom.tag import Tag"),
    ("object", "from pydicom.vr.tagobj import Tag"),
    ("tuple", "from pydicom.vr.tagtup import Tag"),
    ("tupsafe", "from pydicom.vr.tagtupsafe import Tag"),
    ("ntup", "from pydicom.vr.tagnamed import Tag"),
    ("ntupsafe", "from pydicom.vr.tagnamedsafe import Tag"),
    )
]

# Set up tests with more testname, additional setup code, and code to time
Test = namedtuple("Test", "desc setup code")
tests = [Test(*x) for x in (
    ("init tag", "", "t1=Tag(0x300a, 0x01b6)"),
    ("t1==t2", "t1=Tag(0x300a,0x01b6);t2=Tag(0x300a,0x10)", "t1==t2"),
    ("t1==tuple", "t1=Tag(0x300a,0x01b6)", "t1==(0x300a, 0x10)"),
    ("t1<t2", "t1=Tag(0x300a,0x01b6);t2=Tag(0x300a,0x10)", "t1<t2"),
    ("t1<tuple", "t1=Tag(0x300a,0x01b6)", "t1<(0x300a, 0x10)"),
    ("t1<long", "t1=Tag(0x300a,0x01b6)", "t1<0x300a0010"),
    # ("t1>t2", "t1=Tag(0x300a,0x01b6);t2=Tag(0x300a,0x10)", "t1>t2"),
    ("t1.element", "t1=Tag(0x300a,0x01b6)", "t1.element"),
    # ("t1[0]", "t1=Tag(0x300a,0x01b6)", "t1[0]"),
    ("t1[1]", "t1=Tag(0x300a,0x01b6)", "t1[1]"),    
    )
]


# Set up generator for each line, and overall generator to yield the line generator.
# A little more complicated than lists, but allows calling code to print
# each result as it comes.
def test_implementations(test, implementations):
    """Yield the test description, then each result
    for different code implementations a particular test"""
    
    yield test.desc
    
    for impl in implementations:
        setup = impl.imports + ";" + test.setup
        try:
            result = timeit(test.code, setup=setup)
        except Exception:  # Exception to allow KeyboardInterrupt
            result = "N/A"
        yield result
    
def comparison(tests, implementations):
    """Run timeit comparisons and yield generators which in turn yield 
    the column data. The calling code can format a table or html from the lists.
    """

    # Set up the header of the columns 
    headers = ["Test"] + [impl.name for impl in implementations]
    yield iter(headers)
    
    for test in tests:
        yield test_implementations(test, implementations)

        
if __name__ == "__main__":
    import sys
    from datetime import datetime
    
    print "----- Start of timeit tests ---------"
    # Print some system info
    if sys.platform.startswith("darwin"):
        import subprocess
        out = subprocess.Popen('sysctl -a | grep cpu', shell=True,
                               stdout=subprocess.PIPE).communicate()[0]
        out = out.split('\n')
        for line in out:
            if 'cpu.brand_string' in line:
                print "Tests run on:", line.split(":")[-1]
                break
    print "Run date:", datetime.now()
    lines = comparison(tests, implementations)
    first_line = lines.next()
    first_col = "{0!s:<16}".format(first_line.next())
    other_cols = "".join("{0!s:<12}".format(x) for x in first_line) 
    print first_col + other_cols

    for line in lines:
        first_col = "{0!s:<16}".format(line.next())
        print first_col,
        for result in line:
            print "{0!s:<12.5}".format(result),
            sys.stdout.flush() # Force each col to print immediately
        print
        # print first_col + other_cols
